import tkinter as tk
from tkinter import ttk, filedialog, messagebox, scrolledtext
from PIL import Image, ImageTk
import cv2
import numpy as np
import io
import threading
import base64
import os
from openai import OpenAI
import pyautogui
from datetime import datetime
import configparser
import subprocess
import platform
import difflib

# 读取配置文件
config = configparser.ConfigParser()
config.read('config.ini', encoding='utf-8')

# 从配置文件中获取参数
api_key = config['API']['api_key']
base_url = config['API']['base_url']
if "proxy" in config['API']:
    print('有代理')
    os.environ["HTTP_PROXY"] = proxy  # 设置 HTTP 代理
    os.environ["HTTPS_PROXY"] = proxy
#print(os.environ["HTTPS_PROXY"])
model = config['MODEL']['model']
max_tokens = int(config['MODEL']['max_tokens'])
temperature = float(config['MODEL']['temperature'])
prompt = config['PROMPT']['prompt']

# 自定义主题颜色
BG_COLOR = "#f0f8ff"  # 淡蓝色背景
TOOLBAR_BG = "#e0f0ff"  # 工具栏背景
BUTTON_COLOR = "#4b86b4"  # 按钮蓝色
HIGHLIGHT_COLOR = "#63ace5"  # 高亮蓝色
TEXT_COLOR = "#2a4d69"  # 深蓝色文本
FRAME_COLOR = "#d0e7ff"  # 框架背景色

class ImageComparisonApp:
    def __init__(self, root):
        self.root = root
        self.root.title("AI智能图片比对工具")
        self.root.state('zoomed')  # 程序启动时最大化窗口
        self.root.configure(bg=BG_COLOR)
        
        # 设置整体样式
        style = ttk.Style()
        style.configure("TFrame", background=BG_COLOR)
        style.configure("TLabelFrame", background=FRAME_COLOR, foreground=TEXT_COLOR, font=("微软雅黑", 10, "bold"))
        style.configure("TLabel", background=BG_COLOR, foreground=TEXT_COLOR)
        # 按钮文字改为黑色
        style.configure("TButton", background=BUTTON_COLOR, foreground="black", font=("微软雅黑", 10))  # 修改这里
        style.map("TButton", background=[("active", HIGHLIGHT_COLOR)])
        style.configure("Status.TLabel", background="#c0d8f0", foreground=TEXT_COLOR, font=("微软雅黑", 9))
        style.configure("Toolbar.TFrame", background=TOOLBAR_BG)
        
        # 初始化变量
        self.camera = None
        self.camera_active = False
        self.photo_taken = False
        self.selected_image_path = None
        self.photo_image_path = None
        self.roi_image_path = None  # 存储拍照后的ROI截屏路径
        self.image1_size = None  # 存储图片1的尺寸
        self.image1_text = ""    # 存储图片1识别出的文字
        self.image2_text = ""    # 存储图片2识别出的文字
        
        # 创建顶部工具栏
        self.top_toolbar_frame = ttk.Frame(root, padding=10, style="Toolbar.TFrame")
        self.top_toolbar_frame.pack(side=tk.TOP, fill=tk.X, padx=10, pady=5)
        
        # 工具栏标题
        self.title_label = ttk.Label(self.top_toolbar_frame, text="AI智能图片比对工具", 
                                    font=("微软雅黑", 16, "bold"), foreground=TEXT_COLOR)
        self.title_label.pack(side=tk.LEFT, padx=10)
        
        # 添加分隔符
        ttk.Separator(self.top_toolbar_frame, orient=tk.VERTICAL).pack(side=tk.LEFT, fill=tk.Y, padx=10)
        
        # 配置按钮
        self.config_btn = ttk.Button(self.top_toolbar_frame, text="配置", 
                                     command=self.open_config_file, 
                                     width=10)
        self.config_btn.pack(side=tk.LEFT, padx=5)
        
        # 日志按钮
        self.log_btn = ttk.Button(self.top_toolbar_frame, text="日志", 
                                  command=self.open_log_file, 
                                  width=10)
        self.log_btn.pack(side=tk.LEFT, padx=5)
        
        # 图片库按钮
        self.pic_lib_btn = ttk.Button(self.top_toolbar_frame, text="图片库", 
                                      command=self.open_pic_folder, 
                                      width=10)
        self.pic_lib_btn.pack(side=tk.LEFT, padx=5)
        
        # 截屏按钮
        self.screenshot_btn = ttk.Button(self.top_toolbar_frame, text="截屏(获取图片1)", 
                                         command=self.screenshot_and_select_roi,
                                         width=15)
        self.screenshot_btn.pack(side=tk.LEFT, padx=5)
        
        # 将摄像头控制按钮移到顶部工具栏
        self.open_camera_btn = ttk.Button(self.top_toolbar_frame, text="打开摄像头", command=self.toggle_camera, width=12)
        self.open_camera_btn.pack(side=tk.LEFT, padx=5)
        
        self.take_photo_btn = ttk.Button(self.top_toolbar_frame, text="拍照(获取图片2)", command=self.take_photo, state=tk.DISABLED, width=15)
        self.take_photo_btn.pack(side=tk.LEFT, padx=5)
        
        self.submit_btn = ttk.Button(self.top_toolbar_frame, text="提交比对", command=self.submit_photo, state=tk.DISABLED, width=12)
        self.submit_btn.pack(side=tk.LEFT, padx=5)
        
        # 创建主框架
        self.main_frame = ttk.Frame(root, padding=10)
        self.main_frame.pack(side=tk.TOP, fill=tk.BOTH, expand=True, padx=10, pady=5)
        
        # 设置主框架的列权重 - 左侧2/3，右侧1/3
        self.main_frame.columnconfigure(0, weight=2)  # 左侧图片提交区
        self.main_frame.columnconfigure(1, weight=1)  # 右侧分析结果区
        
        # 创建左侧面板 - 图片提交区 (占2/3宽度)
        self.left_frame = ttk.LabelFrame(self.main_frame, text="图片提交区", padding=10)
        self.left_frame.grid(row=0, column=0, sticky="nsew", padx=5, pady=5)
        
        # 图片显示区域 - 水平排列
        self.image_display_frame = ttk.Frame(self.left_frame)
        self.image_display_frame.pack(fill=tk.BOTH, expand=True, pady=5)
        
        # 显示截屏图片 - 图片1 (左侧)
        self.screenshot_frame = ttk.LabelFrame(self.image_display_frame, text="图片1: 截屏区域", padding=5,width=550)
        self.screenshot_frame.pack(side=tk.LEFT, padx=10, pady=5, fill=tk.BOTH, expand=True)
        
        self.screenshot_label = ttk.Label(self.screenshot_frame, text="截屏图片将显示在这里", 
                                         background="#e6f2ff", anchor=tk.CENTER)
        self.screenshot_label.pack(pady=10, fill=tk.BOTH, expand=True)
        self.screenshot_frame.pack_propagate(False)
        
        # 显示拍照图片 - 图片2 (右侧)
        self.photo_frame = ttk.LabelFrame(self.image_display_frame, text="图片2: 摄像头区域", padding=5,width=550)
        self.photo_frame.pack(side=tk.RIGHT, padx=10, pady=5, fill=tk.BOTH, expand=True)
        self.photo_frame.pack_propagate(False)
        
        self.roi_label = ttk.Label(self.photo_frame, text="拍照图片将显示在这里", 
                                  background="#e6f2ff", anchor=tk.CENTER)
        self.roi_label.pack(pady=10, fill=tk.BOTH, expand=True)
        
        # 创建文字识别区域框架（左右布局）
        self.text_comparison_frame = ttk.Frame(self.left_frame)
        self.text_comparison_frame.pack(fill=tk.BOTH, expand=True, pady=5)
        
        # 图片1识别文字（左侧）
        self.image1_text_frame = ttk.LabelFrame(self.text_comparison_frame, text="图片1识别文字", padding=5,width=550)
        self.image1_text_frame.pack(side=tk.LEFT, padx=5, pady=5, fill=tk.BOTH, expand=True)
        
        self.image1_text_area = scrolledtext.ScrolledText(
            self.image1_text_frame, 
            wrap=tk.WORD, 
            height=5,
            font=("微软雅黑", 9),
            background="#f8fcff"
        )
        self.image1_text_area.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
        self.image1_text_area.config(state=tk.DISABLED)
        # 配置文本标签颜色
        self.image1_text_area.tag_config("same", foreground="green")
        self.image1_text_area.tag_config("different", foreground="red")
        self.image1_text_frame.pack_propagate(False)
        
        # 图片2识别文字（右侧）
        self.image2_text_frame = ttk.LabelFrame(self.text_comparison_frame, text="图片2识别文字", padding=5,width=600)
        self.image2_text_frame.pack(side=tk.RIGHT, padx=5, pady=5, fill=tk.BOTH, expand=True)
        
        self.image2_text_area = scrolledtext.ScrolledText(
            self.image2_text_frame, 
            wrap=tk.WORD, 
            height=5,
            font=("微软雅黑", 9),
            background="#f8fcff"
        )
        self.image2_text_area.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
        self.image2_text_area.config(state=tk.DISABLED)
        # 配置文本标签颜色
        self.image2_text_area.tag_config("same", foreground="green")
        self.image2_text_area.tag_config("different", foreground="red")
        
        # 创建右侧面板 - 分析结果区 (占1/3宽度)
        self.right_frame = ttk.LabelFrame(self.main_frame, text="分析结果", padding=10)
        self.right_frame.grid(row=0, column=1, sticky="nsew", padx=5, pady=5)
        
        # 在右侧面板上方添加摄像头实时画面（固定为640*480）
        self.camera_frame = ttk.LabelFrame(self.right_frame, text="摄像头实时画面 (640*480)", padding=5,height=480)
        self.camera_frame.pack(pady=10, fill=tk.X)  # 改为fill=tk.X，不扩展高度
        self.camera_frame.pack_propagate(False)
        
        # 创建一个固定尺寸的Frame来容纳摄像头画面
        self.camera_container = ttk.Frame(self.camera_frame, height=480, width=640)
        self.camera_container.pack(pady=5)
        
        self.camera_label = ttk.Label(self.camera_container, text="摄像头未启动", background="#333", foreground="white")
        self.camera_label.pack(pady=5, fill=tk.BOTH, expand=True)
        
        # 结果显示区域
        self.result_frame = ttk.LabelFrame(self.right_frame, text="比对结果", padding=5)
        self.result_frame.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
        
        self.result_text = scrolledtext.ScrolledText(self.result_frame, wrap=tk.WORD, height=20, 
                                                    font=("微软雅黑", 10), background="#f8fcff")
        self.result_text.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
        self.result_text.config(state=tk.DISABLED)
        
        # 配置文本标签颜色（不同点标红）
        self.result_text.tag_config("different", foreground="red")
        
        # 状态栏
        self.status_bar = ttk.Label(root, text="就绪", relief=tk.SUNKEN, anchor=tk.W, style="Status.TLabel")
        self.status_bar.pack(side=tk.BOTTOM, fill=tk.X)
        
        # 启动摄像头更新
        self.update_camera()
        
    def open_config_file(self):
        """打开配置文件"""
        config_path = "config.ini"
        self.open_file_with_default_app(config_path)
        
    def open_log_file(self):
        """打开日志文件"""
        log_path = "log.log"
        # 如果日志文件不存在，创建一个空文件
        if not os.path.exists(log_path):
            with open(log_path, "w", encoding="utf-8") as f:
                f.write("日志文件创建于: " + datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
        self.open_file_with_default_app(log_path)
        
    def open_pic_folder(self):
        """打开图片库文件夹"""
        folder_path = "pic"
        # 如果文件夹不存在，创建它
        if not os.path.exists(folder_path):
            os.makedirs(folder_path)
        self.open_folder_with_default_app(folder_path)
        
    def open_file_with_default_app(self, file_path):
        """使用系统默认应用打开文件"""
        try:
            if platform.system() == "Windows":
                os.startfile(file_path)
            elif platform.system() == "Darwin":  # macOS
                subprocess.call(("open", file_path))
            else:  # Linux
                subprocess.call(("xdg-open", file_path))
            self.update_status(f"已打开: {file_path}")
        except Exception as e:
            messagebox.showerror("错误", f"无法打开文件: {str(e)}")
            self.update_status(f"打开文件失败: {file_path}")
    
    def open_folder_with_default_app(self, folder_path):
        """使用系统默认文件管理器打开文件夹"""
        try:
            if platform.system() == "Windows":
                os.startfile(folder_path)
            elif platform.system() == "Darwin":  # macOS
                subprocess.call(("open", folder_path))
            else:  # Linux
                subprocess.call(("xdg-open", folder_path))
            self.update_status(f"已打开图片库: {folder_path}")
        except Exception as e:
            messagebox.showerror("错误", f"无法打开文件夹: {str(e)}")
            self.update_status(f"打开文件夹失败: {folder_path}")
    
    def update_status(self, message):
        """更新状态栏信息"""
        self.status_bar.config(text=message)
        self.root.update_idletasks()
    
    def show_image(self, image_path, label_widget, reference_size=None, target_height=None):
        """在指定标签上显示图片"""
        if not image_path or not os.path.exists(image_path):
            label_widget.config(text="图片加载失败", foreground="red")
            return
        
        try:
            image = Image.open(image_path)
            
            # 如果有参考尺寸，调整图片到参考尺寸
            if reference_size:
                # 确保使用高质量缩放
                image = image.resize(reference_size, Image.LANCZOS)
            # 如果指定目标高度，调整图片高度
            elif target_height:
                # 计算新宽度以保持宽高比
                width, height = image.size
                ratio = target_height / height
                new_width = int(width * ratio)
                image = image.resize((new_width, target_height), Image.LANCZOS)
            
            # 调整图片大小以适应标签
            label_width = label_widget.winfo_width() or 300
            label_height = label_widget.winfo_height() or 200
            if label_width < 10: label_width = 300
            if label_height < 10: label_height = 200
            
            # 保持宽高比缩放
            img_width, img_height = image.size
            ratio = min(label_width / img_width, label_height / img_height)
            new_width = int(img_width * ratio)
            new_height = int(img_height * ratio)
            
            image = image.resize((new_width, new_height), Image.LANCZOS)
            photo = ImageTk.PhotoImage(image)
            
            label_widget.config(image=photo)
            label_widget.image = photo
            label_widget.config(text="")
        except Exception as e:
            label_widget.config(text=f"图片加载错误: {str(e)}", foreground="red")
    
    def screenshot_and_select_roi(self):
        """截屏并选择区域 - 获取图片1"""
        self.update_status("截屏中(图片1)...")
        
        # 最小化窗口
        self.root.iconify()
        self.root.update()
        
        # 等待1秒
        cv2.waitKey(1000)
        
        # 截取桌面
        screenshot = pyautogui.screenshot()
        screenshot_np = np.array(screenshot)
        screenshot_cv = cv2.cvtColor(screenshot_np, cv2.COLOR_RGB2BGR)
        
        # 使用selectROI选择区域
        roi = cv2.selectROI("选择区域 (按ESC取消，按空格确认)", screenshot_cv, fromCenter=False, showCrosshair=True)
        cv2.destroyAllWindows()
        
        # 恢复窗口
        self.root.deiconify()
        
        # 检查用户是否取消了选择
        if roi == (0, 0, 0, 0):
            self.update_status("截屏取消")
            return
        
        # 截取ROI区域
        roi_image = screenshot_cv[int(roi[1]):int(roi[1] + roi[3]), int(roi[0]):int(roi[0] + roi[2])]
        
        # 保存ROI图片 - 图片1
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        roi_image_path = f"pic/screenshot_{timestamp}.jpg"
        os.makedirs("pic", exist_ok=True)
        cv2.imwrite(roi_image_path, roi_image)
        
        # 更新选择的图片路径 - 图片1
        self.selected_image_path = roi_image_path
        
        # 获取图片1的尺寸
        self.image1_size = (roi[2], roi[3])
        self.update_status(f"图片1尺寸: {roi[2]}x{roi[3]}")
        
        # 显示截屏图片 - 图片1
        self.show_image(roi_image_path, self.screenshot_label)
        self.update_status(f"图片1已保存: {roi_image_path}")
        
        # 识别图片1中的文字
        self.recognize_image_text(roi_image_path, self.image1_text_area, "图片1")
        
        # 如果图片2也已存在，启用提交按钮
        if self.roi_image_path and os.path.exists(self.roi_image_path):
            self.submit_btn.config(state=tk.NORMAL)
    
    def toggle_camera(self):
        """打开或关闭摄像头"""
        if not self.camera_active:
            try:
                self.camera = cv2.VideoCapture(1)
                if not self.camera.isOpened():
                    messagebox.showerror("错误", "无法打开摄像头！")
                    return
                
                # 设置摄像头分辨率为640x480
                self.camera.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
                self.camera.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)
                
                # 获取实际设置的分辨率
                actual_width = int(self.camera.get(cv2.CAP_PROP_FRAME_WIDTH))
                actual_height = int(self.camera.get(cv2.CAP_PROP_FRAME_HEIGHT))
                self.update_status(f"摄像头已启动，分辨率: {actual_width}x{actual_height}")
                
                self.camera_active = True
                self.open_camera_btn.config(text="关闭摄像头")
                self.take_photo_btn.config(state=tk.NORMAL)
            except Exception as e:
                messagebox.showerror("错误", f"无法打开摄像头: {str(e)}")
        else:
            self.camera_active = False
            if self.camera:
                self.camera.release()
            self.open_camera_btn.config(text="打开摄像头")
            self.take_photo_btn.config(state=tk.DISABLED)
            self.camera_label.config(image="", text="摄像头已关闭")
            self.update_status("摄像头已关闭")
    
    def update_camera(self):
        """定期更新摄像头画面（固定640*480）"""
        if self.camera_active and self.camera and self.camera.isOpened():
            ret, frame = self.camera.read()
            if ret:
                # 调整图像尺寸为640x480
                frame = cv2.resize(frame, (640, 480))
                frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
                img = Image.fromarray(frame)
                
                # 创建PhotoImage
                photo = ImageTk.PhotoImage(image=img)
                
                self.camera_label.config(image=photo)
                self.camera_label.image = photo
                self.camera_label.config(text="")
            else:
                self.camera_active = False
                self.open_camera_btn.config(text="打开摄像头")
                self.take_photo_btn.config(state=tk.DISABLED)
                self.camera_label.config(image="", text="摄像头连接失败")
        
        # 每隔20毫秒再次调用自己
        self.root.after(20, self.update_camera)
    
    def take_photo(self):
        """拍照 - 获取图片2"""
        if not self.camera_active or not self.camera:
            messagebox.showwarning("警告", "请先打开摄像头")
            return
        
        ret, frame = self.camera.read()
        if ret:
            # 确保图片为640x480
            frame = cv2.resize(frame, (640, 480))
            
            timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
            self.photo_image_path = f"pic/photo_{timestamp}.png"
            os.makedirs("pic", exist_ok=True)
            cv2.imwrite(self.photo_image_path, frame)
            self.photo_taken = True
            
            # 显示拍照图片 - 图片2（固定高度为480）
            self.show_image(self.photo_image_path, self.roi_label, target_height=480)
            self.update_status(f"图片2已保存: {self.photo_image_path}")
            
            # 拍照后自动触发ROI截屏
            self.select_roi_from_photo()
    
    def select_roi_from_photo(self):
        """从拍照图片中选择ROI区域 - 完善图片2"""
        if not self.photo_image_path or not os.path.exists(self.photo_image_path):
            messagebox.showerror("错误", "拍照图片不存在")
            return
        
        # 读取拍照图片
        photo_image = cv2.imread(self.photo_image_path)
        if photo_image is None:
            messagebox.showerror("错误", "无法读取拍照图片")
            return
        
        # 最小化窗口（避免遮挡）
        self.root.iconify()
        self.root.update()
        
        # 使用selectROI选择区域
        roi = cv2.selectROI("从拍照图片中选择区域 (按ESC取消，按空格确认)", photo_image, fromCenter=False, showCrosshair=True)
        cv2.destroyAllWindows()
        
        # 恢复窗口
        self.root.deiconify()
        
        # 检查用户是否取消了选择
        if roi == (0, 0, 0, 0):
            self.update_status("ROI选择取消")
            return
        
        # 截取ROI区域
        roi_image = photo_image[int(roi[1]):int(roi[1] + roi[3]), int(roi[0]):int(roi[0] + roi[2])]
        
        # 保存ROI图片 - 图片2
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        roi_image_path = f"pic/roi_{timestamp}.jpg"
        
        # 如果图片1存在且尺寸已知，将图片2缩放到与图片1相同尺寸
        if self.image1_size:
            # 使用高质量缩放
            roi_image = cv2.resize(roi_image, self.image1_size, interpolation=cv2.INTER_LANCZOS4)
            self.update_status(f"图片2已调整为图片1尺寸: {self.image1_size[0]}x{self.image1_size[1]}")
        
        cv2.imwrite(roi_image_path, roi_image)
        
        # 更新ROI图片路径 - 图片2
        self.roi_image_path = roi_image_path
        
        # 显示ROI图片 - 图片2（固定高度为480）
        self.show_image(roi_image_path, self.roi_label, target_height=480)
        self.update_status(f"图片2已完善: {roi_image_path}")
        
        # 识别图片2中的文字
        self.recognize_image_text(roi_image_path, self.image2_text_area, "图片2")
        
        # 如果图片1也已存在，启用提交按钮
        if self.selected_image_path and os.path.exists(self.selected_image_path):
            self.submit_btn.config(state=tk.NORMAL)
    
    def recognize_image_text(self, image_path, text_widget, image_name):
        """识别图片中的文字并显示在指定的文本框中"""
        if not image_path or not os.path.exists(image_path):
            messagebox.showerror("错误", f"{image_name}路径无效")
            return
        
        self.update_status(f"正在识别{image_name}中的文字...")
        
        # 在单独的线程中执行文字识别
        threading.Thread(
            target=self._recognize_image_text_thread, 
            args=(image_path, text_widget, image_name),
            daemon=True
        ).start()
    
    def _recognize_image_text_thread(self, image_path, text_widget, image_name):
        """在后台线程中识别图片文字"""
        try:
            client = OpenAI(
                base_url=base_url,
                api_key=api_key,
                
            )
        except Exception as e:
            error_msg = f"发生错误: {str(e)}\n提示: 无法连接到 {base_url}。这可能是由于网络问题或链接不合法导致的。请检查链接的合法性，适当重试。"
            self.append_to_text_widget(text_widget, error_msg)
            self.update_status(f"{image_name}文字识别失败")
            return
        
        def get_image_data(image_path):
            """获取图片的base64编码数据"""
            image_path = os.path.join(os.getcwd(), image_path)
            if not os.path.exists(image_path):
                raise FileNotFoundError(f"图片文件不存在: {image_path}")
            
            with open(image_path, "rb") as image_file:
                return base64.b64encode(image_file.read()).decode('utf-8')
        
        try:
            # 获取图片数据
            image_data = get_image_data(image_path)
            
            # 构建消息格式 - 包含单张图片
            messages = [
                {
                    "role": "user",
                    "content": [
                        {"type": "text", "text": "请识别图片中的所有文字，包括数字和字母，忽略特殊符号，并将识别结果完整返回。返回格式为json"},
                        {
                            "type": "image_url",
                            "image_url": {"url": f"data:image/jpeg;base64,{image_data}"}
                        }
                    ]
                }
            ]
            
            # 调用视觉模型进行文字识别
            response = client.chat.completions.create(
                model=model,
                messages=messages,
                max_tokens=max_tokens,
                temperature=temperature,
                stream=True,
            )
            
            # 处理流式响应
            recognized_text = ""
            for chunk in response:
                if chunk.choices:
                    content = chunk.choices[0].delta.content
                    if content:
                        recognized_text += content
                        self.append_to_text_widget(text_widget, content)
            
            # 保存识别结果
            if image_name == "图片1":
                self.image1_text = recognized_text
            else:
                self.image2_text = recognized_text
            
            # 记录到日志
            timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
            with open("log.log", "a", encoding="utf-8") as log_file:
                log_file.write(f"[{timestamp}] {image_name}识别结果: {recognized_text}\n")
            
            self.update_status(f"{image_name}文字识别完成")
            
            # 如果两张图片都已识别，进行文字比较
            if self.image1_text and self.image2_text:
                self.compare_texts()
            
        except Exception as e:
            error_msg = f"发生错误: {str(e)}\n"
            self.append_to_text_widget(text_widget, error_msg)
            self.update_status(f"{image_name}文字识别失败")
    
    def append_to_text_widget(self, text_widget, content):
        """向指定文本框追加文本"""
        text_widget.config(state=tk.NORMAL)
        text_widget.insert(tk.END, content)
        text_widget.see(tk.END)  # 滚动到末尾
        text_widget.config(state=tk.DISABLED)
        self.root.update_idletasks()
    
    def submit_photo(self):
        """提交图片1和图片2进行比较"""
        if not self.selected_image_path or not os.path.exists(self.selected_image_path):
            messagebox.showwarning("警告", "请先获取图片1")
            return
        
        if not self.roi_image_path or not os.path.exists(self.roi_image_path):
            messagebox.showwarning("警告", "请先获取图片2")
            return
        
        # 在单独的线程中执行比较操作
        threading.Thread(target=self.compare_images, args=(self.selected_image_path, self.roi_image_path), daemon=True).start()
        self.update_status("正在比较图片1和图片2...")
        self.result_text.config(state=tk.NORMAL)
        self.result_text.delete(1.0, tk.END)
        self.result_text.config(state=tk.DISABLED)
    
    def compare_texts(self):
        """比较两张图片识别出的文字，相同部分标绿，不同部分标红"""
        if not self.image1_text or not self.image2_text:
            return
        
        # 清空文本区域
        self.image1_text_area.config(state=tk.NORMAL)
        self.image1_text_area.delete(1.0, tk.END)
        self.image2_text_area.config(state=tk.NORMAL)
        self.image2_text_area.delete(1.0, tk.END)
        
        # 使用difflib比较文本差异
        d = difflib.Differ()
        diff = list(d.compare(self.image1_text.splitlines(), self.image2_text.splitlines()))
        
        # 处理图片1的文本
        for line in self.image1_text.splitlines():
            self.image1_text_area.insert(tk.END, line + "\n")
        
        # 处理图片2的文本
        for line in self.image2_text.splitlines():
            self.image2_text_area.insert(tk.END, line + "\n")
        
        # 标记相同和不同的部分
        self.highlight_text_differences(self.image1_text_area, self.image1_text, self.image2_text)
        self.highlight_text_differences(self.image2_text_area, self.image2_text, self.image1_text)
        
        self.image1_text_area.config(state=tk.DISABLED)
        self.image2_text_area.config(state=tk.DISABLED)
    
    def highlight_text_differences(self, text_widget, text1, text2):
        """高亮文本差异：相同部分标绿，不同部分标红"""
        text_widget.config(state=tk.NORMAL)
        
        # 逐行比较
        lines1 = text1.splitlines()
        lines2 = text2.splitlines()
        
        start_index = "1.0"
        for i, (line1, line2) in enumerate(zip(lines1, lines2)):
            if i >= len(lines2):
                break
                
            if line1 == line2:
                # 整行相同，标绿色
                end_index = f"{i+1}.0 + {len(line1)}c"
                text_widget.tag_add("same", f"{i+1}.0", end_index)
            else:
                # 逐字符比较
                for j, (char1, char2) in enumerate(zip(line1, line2)):
                    if j >= len(line2):
                        break
                    if char1 == char2:
                        text_widget.tag_add("same", f"{i+1}.{j}", f"{i+1}.{j+1}")
                    else:
                        text_widget.tag_add("different", f"{i+1}.{j}", f"{i+1}.{j+1}")
        
        text_widget.config(state=tk.DISABLED)
    
    def compare_images(self, image_path1, image_path2):
        """
        比较两张图片的相似度并分析它们的主要差异和共同点。
        """
        print('开始比较图片')
        
        try:
            client = OpenAI(
                base_url=base_url,
                api_key=api_key
            )
        except Exception as e:
            error_msg = f"发生错误: {str(e)}\n提示: 无法连接到 {base_url}。这可能是由于网络问题或链接不合法导致的。请检查链接的合法性，适当重试。"
            self.append_result(error_msg)
            self.update_status("连接错误")
            return
        
        def get_image_data(image_path):
            """获取图片的base64编码数据"""
            image_path = os.path.join(os.getcwd(), image_path)
            if not os.path.exists(image_path):
                raise FileNotFoundError(f"图片文件不存在: {image_path}")
            
            with open(image_path, "rb") as image_file:
                return base64.b64encode(image_file.read()).decode('utf-8')
        
        try:
            # 获取两张图片的数据
            image1 = get_image_data(image_path1)
            image2 = get_image_data(image_path2)
            
            # 构建多模态消息格式 - 包含两张图片
            messages = [
                {
                    "role": "user",
                    "content": [
                        {"type": "text", "text": prompt},
                        {
                            "type": "image_url",
                            "image_url": {"url": f"data:image/jpeg;base64,{image1}"}
                        },
                        {
                            "type": "image_url",
                            "image_url": {"url": f"data:image/jpeg;base64,{image2}"}
                        }
                    ]
                }
            ]
            
            # 调用视觉模型进行比较
            response = client.chat.completions.create(
                model=model,
                messages=messages,
                max_tokens=max_tokens,
                temperature=temperature,
                stream=True,
            )
            
            # 在单独的线程中处理流式响应
            threading.Thread(target=self.stream_response_to_gui, args=(response,), daemon=True).start()
        
        except FileNotFoundError as e:
            error_msg = f"错误: {e}\n"
            self.append_result(error_msg)
            self.update_status("文件未找到")
        except Exception as e:
            error_msg = f"发生错误: {str(e)}\n"
            self.append_result(error_msg)
            self.update_status("比较错误")
        
        print('比较结束')
    
    def stream_response_to_gui(self, response):
        """
        在单独的线程中处理流式响应，并实时更新文本框
        """
        try:
            self.append_result("图片比较结果：\n")
            response_text = "图片比较结果：\n"  # 用于存储完整的响应内容
            
            for chunk in response:
                if chunk.choices:
                    content = chunk.choices[0].delta.content
                    if content:
                        print(content, end="", flush=True)
                        self.append_result(content)
                        response_text += content  # 将响应内容追加到字符串中
            
            print("\n流式响应完成")
            # 将完整的响应内容写入日志文件，并加上时间戳
            timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
            with open("log.log", "a", encoding="utf-8") as log_file:
                log_file.write(f"[{timestamp}] {response_text}\n")
            
            # 处理不同点标红
            self.highlight_differences()
            
            self.update_status("比较完成")
        except Exception as e:
            error_msg = f"发生错误: {str(e)}\n"
            self.append_result(error_msg)
            self.update_status("响应错误")
    
    def highlight_differences(self):
        """在分析结果中高亮不同点部分（标红）"""
        self.result_text.config(state=tk.NORMAL)
        
        # 获取所有文本
        all_text = self.result_text.get("1.0", tk.END)
        
        # 查找所有不同点部分（假设以"不同点："开头）
        start_index = "1.0"
        while True:
            # 查找"不同点："位置
            start_pos = self.result_text.search("不同点：", start_index, tk.END, regexp=True)
            if not start_pos:
                break
                
            # 查找下一个标题位置（共同点或结束）
            end_pos = self.result_text.search(r"共同点：|\n\n|$", start_pos, tk.END, regexp=True)
            
            if not end_pos:
                end_pos = tk.END
                
            # 应用红色样式
            self.result_text.tag_add("different", start_pos, end_pos)
            
            # 更新搜索起始位置
            start_index = end_pos
            
        self.result_text.config(state=tk.DISABLED)
    
    def append_result(self, text):
        """向结果文本框追加文本"""
        self.result_text.config(state=tk.NORMAL)
        self.result_text.insert(tk.END, text)
        self.result_text.see(tk.END)  # 滚动到末尾
        self.result_text.config(state=tk.DISABLED)
        self.root.update_idletasks()

if __name__ == "__main__":
    root = tk.Tk()
    app = ImageComparisonApp(root)
    
    # 设置窗口图标（可选）
    try:
        root.iconbitmap("icon.ico")  # 如果有图标文件的话
    except:
        pass
    
    root.mainloop()
